/* ----------------------------------------------------------------------------

	pax.widget.tabset.js Copyright (C) 2002, 2004, 2006, 2008 Mikkel Bergmann, Pointful

	Licence
	-------
	
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

	See lgpl.txt for licence details

---------------------------------------------------------------------------- */


/*
	Script: pax.widget.tabset
		This is a widget that sets up a tabset
		
	Author:
		Mikkel Bergmann, <http://www.pointful.com>
		
	Note:
		It would appear that FF3 has a bug with global name space evaluation, which is causing the
		tabset demo to fail on FF3:
		
			http://groups.google.com/group/mozilla.dev.tech.js-engine.rhino/msg/bffaa0f603ee167b
*/

/*
		TODO: Create "deleteTab" and "addTab" methods, for dynamic creation of tabs.
		TODO: Add a 'close tab' button on the right side, which should use the new "deleteTab" to "close" it..
*/


var pax = pax || {};
pax.widget = pax.widget || {};
pax.widget.tabset = pax.widget.tabset || {};

/*	Property: pax.widget.tabset.defaultTabAttribute
	The attribute we use by default to identify a tab, in static tabs	*/
pax.widget.tabset.defaultTabAttribute = 'TITLE';

/*	Method: pax.widget.tabset.init
	Displays the tabset on a specifed element

	Parameters:
		element - The target element for the output
		tabSpaces - Optionally specify how many spaces per tab, default = 4

	Example:
		(start code)
			<form>
				<div id='pax.widget.tabset.example1'>
					<fieldset class='pFieldset' style='float: left; margin-right: 20px;' alt='Personal details'>
						<label class='pLabel' for="firstName">First name</label>	<input name="firstName" id="firstName" type="text" value=""><br>
						<label class='pLabel' for="lastName">Last name</label>		<input name="lastName" id="lastName" type="text" value=""><br>
						<label class='pLabel' for="logon">Logon</label>				<input name="logon" type="text" value=""><br>
						<label class='pLabel' for="dob">Date of birth</label>		<input name="dob" id="dob" type="text" value="" size="25" maxlength="25"><br>
						<label class='pLabel' for="email">Email</label>				<input name="email" id="email" type="text" size="30" value=""><br>
						<label class='pLabel' for="phone">Phone</label>				<input name="phone" id="phone" type="text" size="30" value=""><br>
					</fieldset>
					<fieldset class='pFieldset' style='float: left; margin-right: 20px;' alt='Notes'>
						<label class='pLabel' for="notes">Notes</label>				<textarea name="notes" id="notes"></textarea><br>
					</fieldset>
				</div>
				<button type='submit' name='SaveButton'>Save</button>
			</form>

			[:.
				pax.load.onloaded( function() {
					pax.widget.tabset.init( pax.$( 'pax.widget.tabset.example1' ), {
						height: 200,
						showToggle: true,
						tabAttribute: 'ALT'
					} );
				} );
			:]
		(end)
		This would show a tabset with two tabs.
	
	
		Note: When we init tabsets contained inside eachother, the surrounding tabset will pick up the inner tabsets title attribute, and create a new tab...
		
		Workaround: use a different tag, such as 'ALT', by setting the tabAttribute.
	
	
*/
pax.widget.tabset.init = function( element, args ) {
	args = ( typeof( args ) != 'undefined' )? args: {};
	args.tabs = ( typeof( args.tabs ) != 'undefined' )? args.tabs: [];
	args.onactivate = ( typeof( args.onactivate ) != 'undefined' )? args.onactivate: {};
	args.dynamicTabsFirst = ( typeof( args.dynamicTabsFirst ) != 'undefined' )? args.dynamicTabsFirst: true;
	
	//	Attribute used to identify a tab, and set the title of it, eg: <div title='My tab'>...</div>
	args.tabAttribute = ( typeof( args.tabAttribute ) != 'undefined' )? args.tabAttribute: pax.widget.tabset.defaultTabAttribute;

	//	Create a unique ID for the tabset
	var uniqueTabsetID = pax.getNextId() + '_tabset';
	
	//	Create a temporary container, and element DIV for our tab-elements
	pax.widget.tabset.elementTabs = [];
	var myTempDiv = pax.util.genElement('DIV', { id: uniqueTabsetID + 'tempContainer' } );
	pax.$(document.body).appendChild( myTempDiv );
	
	//	Iterate through elements in the element, and use the elements that have a predetermined attribute, as tabs.
	var staticTabs = [];
	var staticElements = [];
	var elementList = element.getElementsByTagName('*');
	
	//	Only use elements that have the tabAttribute
	//	TODO: Perhaps just hide the unwanted elements?
	for (var i in elementList) {
		var ele = elementList[i];
		//	We use the specified attribute to identfy a tab, default is 'title'
		if (ele && ele.getAttribute ) {
			var title = ele.getAttribute( args.tabAttribute );
			if( title && title != '' )staticElements.push(ele);
		}
	}
	
	//	Iterate on relevant elements
	for( var i = 0; i < staticElements.length; i++ ) {
		var ele = staticElements[i];
		
		//	Get title, and create the tab, including an onactivate function
		var title = ele.getAttribute( args.tabAttribute );
		var onactivate = ( pax.util.hasKey( title, args.onactivate ) )? args.onactivate[title]: false;
		
		//	Move tab elements into temp element, to allow us to use a template on top of the main element.
		myTempDiv.appendChild( ele );
		
		staticTabs.push( {
			title: title, 
			//	content: ele.innerHTML,
			content: ele,				//	Using the complete element.
			onactivate: onactivate
		} );
	}
	
	//	Add static and dynamic tabs (in the correct order)
	if(	args.dynamicTabsFirst ) {
		for( var t = 0; t < staticTabs.length; t++ )args.tabs.push( staticTabs[t] );
	} else {
		var newTabs = staticTabs;
		for( var t = 0; t < args.tabs.length; t++ )newTabs.push( args.tabs[t] );
		args.tabs = newTabs;
	}
	
	//	The model
	var model = pax.defaultArgs( {
		tabAttribute: pax.widget.tabset.defaultTabAttribute,
		tabs: [],
		tabID: [],
		width: 600,
		height: 400,
		selectedTab: 0,
		onactivate: {},
		showToggle: false,
		toggleAll: false,
		element: element,
		renderTabContent: true,		//	If we should render tabs contents (ie: treat it as a template automatically?)
		uniqueID: uniqueTabsetID,

		bindClasses: {
			pTabsetHeader: {
				click: function(e) {
					var target = e.target || window.event.srcElement;
					if( ! pax.util.hasClassName( target, 'headerContent' ) )return false;
					var tabID = target.id;
					pax.$(tabID).model.showTab( tabID );
				},
				mouseover: function(e) {
					var target = e.target || window.event.srcElement;
					pax.util.addClassName( target, 'pTabsetHover' );
				},
				mouseout: function(e) {
					var target = e.target || window.event.srcElement;
					pax.util.removeClassName( target, 'pTabsetHover' );
				}
			}
		},
		
		//	Internally bound IDs
		internalBindIds: {
			toggle: {
				click: function( e ) {
					if( model.toggleAll ) {
						//	Show the selected tab
						model.showTab( model.tabID[model.selectedTab] );
						model.toggleAll = false;
					} else {
						//	Show all tabs
						for( var i in model.tabID ) {
							model.showTab( model.tabID[i], true );
						}
						model.toggleAll = true;
					}
				}
			}
		},
		
		_show: function( tabID ) {
			pax.$( tabID ).style.display = '';
		},
		
		_hide: function( tabID ) {
			pax.$( tabID ).style.display = 'none';
		},
		
		//	Shows a tab, when header is clicked.
		showTab: function( tabID, toggleMode ) {
			toggleMode = ( toggleMode != null )? toggleMode : false;
			//	Warning: using naming convention here... Hide all tabs, bar the one with tabID
			var targetTabContentID = tabID.replace( '_tab_', '_tabcontent_' );
			var tabContentContainerID = model.uniqueID + '_tabcontainer';
			
			for( var i in this.tabID ) {
				var tabContentID = this.tabID[i].replace( '_tab_', '_tabcontent_' );
				if( this.tabID[i] == tabID ) {
					//	If we're using lazy loading for ajax tabs...
					//	Note: This is loaded in the initial rendring, if not lazy.
					if( pax.util.getType( this.tabs[i].content ) == 'object' ) {
						var con = this.tabs[i].content;
						//	Set overflow to auto on scroll container, as we remove this for iFrames. Also reset class for the content container
						pax.util.addClassName( pax.$( this.uniqueID + '_tabscroll' ), 'pTabsetScroll' );
						pax.util.removeClassName( pax.$( tabContentID ), 'pTabsetContentIFrame' );
						pax.util.addClassName( pax.$( tabContentID ), 'pTabsetContent' );
						
						if( con.lazy ) {
							//	Note: using GET, the browser will cache the content by default
							pax.get( con.url, function( xml, txt, url ) {
								//	Assume we have a template, and render it - not sure where we get data for the template from?
								pax.template.render( txt, { target: pax.$( targetTabContentID ) } );
							}, 'Lazy load ' + con.url, false, false );
						} else if( con.frame ) {
							//	Using a frame to display content, remove scrollbars of container, as the iframe uses 
							//	it's own; We automatically restore the scrollbars, once we go to a different tab.
							if( ! toggleMode )pax.util.removeClassName( pax.$( this.uniqueID + '_tabscroll' ), 'pTabsetScroll' );
							//	Set the class for the container to fit iframe content
							pax.util.swapClassName( pax.$( tabContentID ), 'pTabsetContent', 'pTabsetContentIFrame' );
						}
					}
					if( ! toggleMode ) {
						pax.util.addClassName( pax.$( this.tabID[i] ).parentNode, 'pTabsetHeaderShown' );
						model.selectedTab = i;
					}
					//	onBeforeActivate
					this._show( tabContentID );
					//	onActivate
					if( pax.util.getType( this.tabs[i].onactivate ) == 'function' )this.tabs[i].onactivate( tabID );
				} else {
					pax.util.removeClassName( pax.$( this.tabID[i] ).parentNode, 'pTabsetHeaderShown' );
					if( ! toggleMode )this._hide( tabContentID );
				}
			}
		}
	}, args );

	//	Initialise the widget
	var tabset = pax.widget.init( {
		model: model,
		template: function() { return pax.widget.tabset.template( tabset ) },
		target: pax.$( model.element )
	} );
	
	model.tabset = tabset;
	tabset.render();

	//	Add the model into each tab element
	for( var i in model.tabID )pax.$( model.tabID[i] ).model = tabset.model;

	//	Attach the elements - we only do this to allow iFrames in IE, for HTML editors such as 
	//	TinyMCE and FCKEditor
	for( var i = 0; i < pax.widget.tabset.elementTabs.length; i++ ) {
		var xElement = pax.widget.tabset.elementTabs[i]['element'];
		if( xElement ) {
			var xTarget = pax.$( pax.widget.tabset.elementTabs[i]['tabID'] );
			while (xElement.childNodes.length > 0) 
				xTarget.appendChild(xElement.firstChild);
		}
	}

	//	Reset container and remove element
	pax.util.removeElement( myTempDiv );

	tabset.internalBindIds( element, tabset.model.internalBindIds );	// Bind specific IDs, automatically post-fixed with '_' + grid.model.target.id
	tabset.bindClassNames( element, tabset.model.bindClasses );			// Bind specific class names 
	
	//	Show the selectedTab
	if( model.tabs.length > 0 ) {
		model.showTab( model.tabID[model.selectedTab] );
	} else {
		pax.criticalError( 'pax.widget.tabset.init: No tabs defined for ID: [' + element.id + '], please check your initialisation function.' );
	}
	
	return tabset;
};


/*	Method: pax.widget.tabset.destroy
	This is a private method to clean up the DOM, and any widgets that are used here
*/
pax.widget.tabset.destroy = function( tabset ) {
	pax.box.hide( pax.$(tabset.model.element.id + '_tabset') );
	tabset._destroy();
};

/*	Method: pax.widget.tabset.template
	Returns a PAX template for the tabset
	
*/
pax.widget.tabset.template = function( tabset ) {

	var tabsetTemplate = "" +
		"<div style='width: [:= tabset.model.width :][:= ( typeof( tabset.model.width ) != 'string' )? 'px': '' :]' class='pTabset'>" +
		"	<div class='pTabsetHeader'>" +
		"		<div style='width: [:= tabset.model.width :]'>" +
		"			<table cellpadding='0' cellspacing='0'>" +
		"				<tr width='100%'>" +
		"					<td width='100%'>" +
		"						<table cellpadding='0' cellspacing='0'>" +
		"							<tr>" +
		"								[:	for( var i = 0; i < tabset.model.tabs.length; i++ ) { var tab = tabset.model.tabs[i];" +
		"										if( !pax.util.hasValue( tab.title, tabset.model.ignoreCols) ) {" +
		"											var tabID = tabset.model.uniqueID + '_tab_' + i;" +
		"								:]" +
		"								<td>" +
		"									<div class='pTabsetCell headerContent' unselectable='on' id='[:= tabID :]'>[:= _caps( tab.title ) :]</div>" +
		"								</td>" +
		"								[:	tabset.model.tabID.push( tabID );	" +	//	Add the tab ID into the model
		"										}" +
		"									}" +
		"								:]" +
		"							</tr>" +
		"						</table>" +		
		"					</td>" +
		"					[: if( tabset.model.showToggle ) { :]" +
		"					<td><div id='toggle_[:= element.id :]'>&nbsp;</div>" +	//	Add toggle button
		"					</td>" +
		"					[: } :]" +
		"					[:. " +
		"						if( tabset.model.showToggle ) {" +
		"							tabset.useWidget(pax.widget.button.init( pax.$( 'toggle_' + element.id ), { " +
		"								baseClass: 'pButtonWindow arrowDown', " +
		"								showChrome: false, " +
		"								width: '18px', " +
		"								height: '18px' " +
		"							} ));" +
		"						}" +
		"					:] " +
		"				</tr>" +
		"			</table>" +		
		"		</div>		" +
		"	</div>" +
		"	<div class='pTabsetScroll' id='[:= tabset.model.uniqueID :]_tabscroll' style='height: [:= tabset.model.height :][:= ( typeof( tabset.model.height ) != 'string' )? 'px': '' :]'>" +
		"		<div id='[:= tabset.model.uniqueID :]_tabcontainer'> :]" +
		"		[:	for( var i = 0; i < tabset.model.tabs.length; i++ ) { var con = tabset.model.tabs[i].content; var thisTabId = tabset.model.uniqueID + '_tabcontent_' + i;	:]" +
		"			<div class='pTabsetContent' id='[:= thisTabId :]' style='display: none'>" +
		"			[:	if( pax.util.getType( con ) == 'element' ) { " +	//	If con is element, push into element tabs list
		"					pax.widget.tabset.elementTabs.push( { tabID: thisTabId, element: con } ); " +
		"			} else if( pax.util.getType( con ) == 'object' ) { :]" +	//	If con is obj use ajax or iframe, else render
		"				[: if( con.lazy == true ) {	:]" +
		"					Loading, please wait..." +	//	Lazy loading is done in the showTab method.
		"				[: } else if( con.url ) {	:]" +
		"					[:= load( con.url, 'Loading ajax tab' ) :]" +
		"				[: } else if( con.frame ) {	:]" +
		"					<iframe src='[:= con.frame :]' frameBorder='0' scrolling='auto' style='border: 0; padding: 0; margin: 0; width: [:= tabset.model.width :]; height: [:= tabset.model.height :]px;'></iframe>" +
		"				[: }	:]" +
		"			[:	} else if( pax.util.getType( con ) != false ) {	:]" +
		"				[:= (tabset.model.renderTabContent)? push( con, tabset ): con :]" +
		"			[:	}	:]" +
		"			</div>" +
		"		[:	}	:]" +
		"		</div>" +
		"	</div>" +
		"</div>" +
	"";
	
	return tabsetTemplate;
};